#include "PPaint.h"
#include <math.h>
#include <stdio.h>

PPaint::PPaint()
{
	bmih.biSize=sizeof(BITMAPINFOHEADER);
	bmih.biBitCount=24;
	bmih.biPlanes=1;
	bmih.biCompression=BI_RGB;
	bmih.biSizeImage=0;
	bmih.biXPelsPerMeter=0;
	bmih.biYPelsPerMeter=0;
	bmih.biClrUsed=0;
	bmih.biClrImportant=0;
	pbyte=NULL;
	_bmp=NULL;
	_hdc=NULL;
	_font=NULL;
}
PPaint::PPaint(int cx,int cy)
{
	bmih.biSize=sizeof(BITMAPINFOHEADER);
	bmih.biHeight=cy;
	bmih.biWidth=cx;
	bmih.biBitCount=24;
	bmih.biPlanes=1;
	bmih.biCompression=BI_RGB;
	bmih.biSizeImage=0;
	bmih.biXPelsPerMeter=0;
	bmih.biYPelsPerMeter=0;
	bmih.biClrUsed=0;
	bmih.biClrImportant=0;
	_font = NULL;
	_bmp=CreateDIBSection(NULL,(BITMAPINFO * )(&bmih),DIB_RGB_COLORS,(void**)&pbyte,NULL,0);
	_hdc=CreateCompatibleDC(NULL);
	SelectObject(_hdc,_bmp);
	SetBkMode(_hdc,TRANSPARENT);
}
PPaint::~PPaint()
{
	bmih.biHeight=0;
	bmih.biWidth=0;
	if(_bmp) DeleteObject(_bmp);
	if(_hdc) DeleteObject(_hdc);
}
void PPaint::reset(int cx,int cy)
{
	if(cx!=bmih.biWidth || cy!=bmih.biHeight)
	{
		bmih.biHeight=cy;
		bmih.biWidth=cx;
		if(_bmp) DeleteObject(_bmp);
		_bmp=CreateDIBSection(NULL,(BITMAPINFO * )(&bmih),DIB_RGB_COLORS,(void**)&pbyte,NULL,0);
		if(_hdc==NULL) _hdc=CreateCompatibleDC(NULL);
		SelectObject(_hdc,_bmp);
		SetBkMode(_hdc,TRANSPARENT);
		if(_font) SelectObject(_hdc,_font);
	}
}
PPaint & PPaint::operator=(const PPaint &p)
{
	reset(p.width(),p.height());
	int len=(width()*3+3)/4*height();
	int *pd=(int *)pbyte;
	int *ps=(int *)p.buffer();
	for(int i=0;i<len;++i) pd[i]=ps[i];
	return *this;
}

void PPaint::reflect(const PU8Image3& image, const byte* plut)
{
	int w=width()< image.width() ? width(): image.width();
	int h=height()< image.height() ? height(): image.height();
	for(int y=0;y<h;++y)
	{
		byte *pt=row(y);
		const u8v3* p= image.row(y);
		for(int x=0;x<w;++x)
		{
			pt[x*3] = plut[int(p[x][0])];
			pt[x*3+1] = plut[int(p[x][1])];
			pt[x*3+2] = plut[int(p[x][2])];
		}
	}
}
PU8Image3 PPaint::putImage() const
{
	int w = width(), h = height();
	PU8Image3 image(w, h);
	for (int y = 0; y < h; ++y)
	{
		u8v3* pt = (u8v3*)row(y);
		u8v3* p = image.row(y);
		for (int x = 0; x < w; ++x)
		{
			p[x] = pt[x];
		}
	}
	return image;
}
void PPaint::lut(const byte plut[256])
{
	for(int y=0;y<height();++y)
	{
		byte *p=row(y);
		for(int x=0;x<width();++x)
		{
			p[x*3]=plut[p[x*3]];
			p[x*3+1]=plut[p[x*3+1]];
			p[x*3+2]=plut[p[x*3+2]];
		}
	}
}
void PPaint::lut(double a,double b)
{
	byte u[256];
	for(int i=0;i<256;++i)
	{
		int m=int(a*i+b+0.5);
		if(m<0) u[i]=0;
		else if(m>255) u[i]=255;
		else u[i]=byte(m);
	}
	lut(u);
}

void PPaint::drawLine(int x1,int y1,int x2,int y2, PColor color,int w)
{
	HPEN pen=CreatePen(PS_SOLID,w,color.colorref());
	SelectObject(_hdc,pen);
	MoveToEx(_hdc,x1,y1,0);
	LineTo(_hdc,x2,y2);
	DeleteObject(pen);
}
void PPaint::drawRectangle(int x1,int y1,int x2,int y2, PColor color,int w)
{
	HPEN pen=CreatePen(PS_SOLID,w,color.colorref());
	SelectObject(_hdc,pen);
	MoveToEx(_hdc,x1,y1,0);
	LineTo(_hdc,x2,y1);
	LineTo(_hdc,x2,y2);
	LineTo(_hdc,x1,y2);
	LineTo(_hdc,x1,y1);
	DeleteObject(pen);
}
void PPaint::fill(PColor color)
{
	RECT rect;
	SetRect(&rect,0,0,width(),height());
	HBRUSH brush=CreateSolidBrush(color.colorref());
	FillRect(_hdc,&rect,brush);
	DeleteObject(brush);
}
void PPaint::fillRectangle(int x1,int y1,int x2,int y2, PColor color)
{
	RECT rect;
	SetRect(&rect,x1,y1,x2,y2);
	HBRUSH brush=CreateSolidBrush(color.colorref());
	FillRect(_hdc,&rect,brush);
	DeleteObject(brush);
}
void PPaint::drawEllipse(int x,int y,int a,int b, PColor color,int w)
{
	HPEN pen=CreatePen(PS_SOLID,w,color.colorref());
	SelectObject(_hdc,pen);
	Arc(_hdc,x-a,y-b,x+a,y+b,x-a,y,x+a,y);
	Arc(_hdc,x-a,y-b,x+a,y+b,x+a,y,x-a,y);
	DeleteObject(pen);
}
void PPaint::drawEllipse2(int x,int y,int a,int b,double alpha, PColor color,int w)
{
	HPEN pen=CreatePen(PS_SOLID,w,color.colorref());
	SelectObject(_hdc,pen);
	int num=a+b;
	if(num<15) num=15;
	POINT * point=new POINT[num];
	double t=pi*2.0/(num-1);
	double sinalpha=sin(alpha);
	double cosalpha=cos(alpha);
	for(int i=0;i<num;++i)
	{
		double xp=a*cos(t*i);
		double yp=b*sin(t*i);
		double xt=xp*cosalpha-yp*sinalpha+x;
		double yt=xp*sinalpha+yp*cosalpha+y;
		point[i].x=int(xt);
		point[i].y=int(yt);
	}
	Polyline(_hdc,point,num);
	DeleteObject(pen);
	delete[] point;
}
void PPaint::drawRectangle2(int x,int y,int a,int b,double alpha, PColor color,int w)
{
	HPEN pen=CreatePen(PS_SOLID,w,color.colorref());
	SelectObject(_hdc,pen);
	POINT point[5];
	double sinalpha=sin(alpha);
	double cosalpha=cos(alpha);

	double xt=(-a)*cosalpha-(-b)*sinalpha+x;
	double yt=(-a)*sinalpha+(-b)*cosalpha+y;
	point[0].x=int(xt);
	point[0].y=int(yt);
	point[4].x=int(xt);
	point[4].y=int(yt);
	xt=(-a)*cosalpha-(b)*sinalpha+x;
	yt=(-a)*sinalpha+(b)*cosalpha+y;
	point[1].x=int(xt);
	point[1].y=int(yt);
	xt=(a)*cosalpha-(b)*sinalpha+x;
	yt=(a)*sinalpha+(b)*cosalpha+y;
	point[2].x=int(xt);
	point[2].y=int(yt);
	xt=(a)*cosalpha-(-b)*sinalpha+x;
	yt=(a)*sinalpha+(-b)*cosalpha+y;
	point[3].x=int(xt);
	point[3].y=int(yt);

	Polyline(_hdc,point,5);
	DeleteObject(pen);
}
void PPaint::drawCross(int x,int y,int l, PColor color, int w)
{
	HPEN pen=CreatePen(PS_SOLID,w,color.colorref());
	SelectObject(_hdc,pen);
	MoveToEx(_hdc,x-l,y,0);
	LineTo(_hdc,x+l,y);
	MoveToEx(_hdc,x,y-l,0);
	LineTo(_hdc,x,y+l);
	DeleteObject(pen);
}
void PPaint::drawArrow(int x,int y,int l,double a, PColor color)
{
	int px1=x+int(-l*cos(a)-l*0.4*sin(a));
	int py1=y+int(-l*sin(a)+l*0.4*cos(a));
	int px2=x+int(-l*cos(a)+l*0.4*sin(a));
	int py2=y+int(-l*sin(a)-l*0.4*cos(a));

	HPEN pen=CreatePen(PS_SOLID,1,color.colorref());
	SelectObject(_hdc,pen);
	MoveToEx(_hdc,x,y,0);
	LineTo(_hdc,px1,py1);
	MoveToEx(_hdc,x,y,0);
	LineTo(_hdc,px2,py2);
	DeleteObject(pen);
}
void PPaint::drawText(const TCHAR *text,int len,int x,int y, PColor color)
{
	SetTextColor(_hdc,color.colorref());
	TextOut(_hdc,x,y,text,len);
}
void PPaint::drawPointset(const PPointset &pointset, PColor color)
{
	for(int i=0;i<pointset.count();++i)
	{
		SetPixel(_hdc,pointset[i].x,pointset[i].y,color.colorref());
	}
}
void PPaint::drawRegion(const PRegion &region,const PDPoint &spoint, PColor color)
{
	RECT rect;
	HBRUSH back=CreateSolidBrush(color.colorref());
	PRegionPos pos(region.begin());
	PRegionItem item;
	while(region.getRange(pos,item))
	{
		int y=item.y+spoint.y;
		int x0=item.x0+spoint.x;
		int x1=item.x1+spoint.x;
		if(y>=0 && y<height() && x1>=0 && x0<width())
		{
			SetRect(&rect,x0,y,x1,y+1);
			FillRect(_hdc,&rect, back);
		}
	}
	DeleteObject(back);
}
void PPaint::drawPolygon(const PPointset& polygon, PColor color)
{
	if (polygon.isEmpty()) return;

	HPEN pen=CreatePen(PS_SOLID,1,color.colorref());
	SelectObject(_hdc,pen);

	PDPoint p = polygon[0];
	for (int i = 1; i < polygon.count(); ++i)
	{
		MoveToEx(_hdc, p.x, p.y, 0);
		LineTo(_hdc, polygon[i].x, polygon[i].y);
	}
	MoveToEx(_hdc, p.x, p.y, 0);
	LineTo(_hdc, polygon[0].x, polygon[0].y);

	DeleteObject(pen);
}
void PPaint::drawMask(const byte *pmask,int mw,int mh,int x,int y, PColor color)
{
	for(int i=0;i<mh;++i)
	{
		byte *pt=row(y+i);
		for(int j=0;j<mw;++j)
		{
			byte* p = pt + (x + j) * 3;
			if(pmask[i*mw+j])
			{
				p[0] = color[0];
				p[1] = color[1];
				p[2] = color[2];
			}
		}
	}
}
